package xj.graph2d.graph;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import xj.lang.CodeWriter;

public class AbstractHyperGraphNode <NodeType extends GraphNode<EdgeType>, 
				     EdgeType extends GraphEdge<NodeType>>
  extends AbstractGraphNode<EdgeType> 
  implements HyperGraphNode<NodeType, EdgeType> {

  public AbstractHyperGraphNode(Subgraph<NodeType, EdgeType> subgraph) {
    this.subgraph = subgraph;
    if (subgraph instanceof AbstractSubgraph) {
      AbstractSubgraph<NodeType, EdgeType> asub = 
	(AbstractSubgraph<NodeType, EdgeType>) subgraph;
      // subgraph.setName(getName());
      asub.setId(id);
    }
  }

  public AbstractHyperGraphNode() {
    AbstractSubgraph<NodeType, EdgeType> asub = 
      new AbstractSubgraph<NodeType, EdgeType>();
    asub.setId(id);
    subgraph = asub;
  }

  public boolean isExpanded() {
    return expanded;
  }

  public void expand() {
    if (!expanded) {
      expanded = true;

    }
  }

  public void collapse() {
    if (expanded) {
      expanded = false;
    }
  }

  /*
   * public boolean isDirected() { if (subgraph != null) { return
   * subgraph.isDirected(); } else { return true; } }
   * 
   * public void setDirected(boolean directed) { if (subgraph != null) {
   * subgraph.setDirected(directed); } }
   * 
   * public boolean isStrict() { if (subgraph != null) { return
   * subgraph.isStrict(); } else { return true; } }
   * 
   * public void setStrict(boolean strict) { if (subgraph != null) {
   * subgraph.setStrict(strict); } }
   */

  public boolean addNode(NodeType node) {
    if (subgraph != null) {
      return subgraph.addNode(node);
    } else {
      return false;
    }
  }

  public boolean removeNode(NodeType node) {
    if (subgraph != null) {
      return subgraph.removeNode(node);
    } else {
      return false;
    }
  }

  public boolean removeNode(NodeType node, boolean disconnect) {
    if (subgraph != null) {
      return subgraph.removeNode(node, disconnect);
    } else {
      return false;
    }
  }

  public NodeType removeNode(String name) {
    if (subgraph != null) {
      return subgraph.removeNode(name);
    } else {
      return null;
    }
  }

  public NodeType removeNode(String name, boolean disconnect) {
    if (subgraph != null) {
      return subgraph.removeNode(name, disconnect);
    } else {
      return null;
    }
  }

  public boolean addEdge(EdgeType edge) {
    return addEdge(edge, false);
  }

  public boolean addEdge(EdgeType edge, boolean allowDuplicate) {
    if (subgraph != null) {
      return subgraph.addEdge(edge);
    } else {
      return false;
    }
  }

  public boolean removeEdge(EdgeType edge) {
    if (subgraph != null) {
      return subgraph.removeEdge(edge);
    } else {
      return false;
    }
  }

  public EdgeType removeEdge(String name) {
    if (subgraph != null) {
      return subgraph.removeEdge(name);
    } else {
      return null;
    }
  }

  public NodeType disconnectDestination(EdgeType edge) {
    if (subgraph != null) {
      return subgraph.disconnectDestination(edge);
    } else {
      return null;
    }
  }

  public NodeType disconnectSource(EdgeType edge) {
    if (subgraph != null) {
      return subgraph.disconnectSource(edge);
    } else {
      return null;
    }
  }

  public void connectDestination(EdgeType edge, NodeType node) {
    if (subgraph != null) {
      subgraph.connectDestination(edge, node);
    }
  }

  public void connectSource(EdgeType edge, NodeType node) {
    if (subgraph != null) {
      subgraph.connectSource(edge, node);
    }
  }

  public void reverseEdgeDirection(EdgeType edge) { 
    if (subgraph != null) {
      subgraph.reverseEdgeDirection(edge);
    }
  }

  public void moveEdgeToSubgraph(EdgeType edge, 
				 Subgraph<NodeType, EdgeType> subg) {
    if (subgraph != null) {
      subgraph.moveEdgeToSubgraph(edge, subg);
    }
  }

  public boolean isAllowDanglingEdges() {
    if (subgraph != null) {
      return subgraph.isAllowDanglingEdges();
    } else {
      return false;
    }
  }

  public void setAllowDanglingEdges(boolean allowDanglingEdges) {
    if (subgraph != null) {
      subgraph.setAllowDanglingEdges(allowDanglingEdges);
    }
  }

  public boolean isAllowDuplicateEdges() {
    if (subgraph != null) {
      return subgraph.isAllowDuplicateEdges();
    } else {
      return false;
    }
  }

  public void setAllowDuplicateEdges(boolean allowDuplicateEdges) {
    if (subgraph != null) {
      subgraph.setAllowDuplicateEdges(allowDuplicateEdges);
    }
  }

  public void removeAllNodes() {
    if (subgraph != null) {
      subgraph.removeAllNodes();
    }
  }

  public int getNumberOfNodes() {
    if (subgraph != null) {
      return subgraph.getNumberOfNodes();
    } else {
      return 0;
    }
  }

  public int getNumberOfEdges() {
    if (subgraph != null) {
      return subgraph.getNumberOfEdges();
    } else {
      return 0;
    }
  }

  public boolean isEmpty() {
    if (subgraph != null) {
      return subgraph.isEmpty();
    } else {
      return true;
    }
  }

  public boolean addSubgraph(Subgraph subg) {
    if (subgraph != null) {
      return subgraph.addSubgraph(subg);
    } else {
      return false;
    }
  }

  public boolean removeSubgraph(Subgraph subg) {
    if (subgraph != null) {
      return subgraph.removeSubgraph(subg);
    } else {
      return false;
    }
  }

  public boolean removeSubgraph(String name) {
    if (subgraph != null) {
      return subgraph.removeSubgraph(name);
    } else {
      return false;
    }
  }

  public boolean containsNode(NodeType node) {
    if (subgraph != null) {
      return subgraph.containsNode(node);
    }
    return false;
  }

  public boolean containsEdge(EdgeType edge) {
    if (subgraph != null) {
      return subgraph.containsEdge(edge);
    }
    return false;
  }

  public Set<NodeType> allSubnodes() {
    if (subgraph != null) {
      return subgraph.allSubnodes();
    }
    return null;
  }

  public boolean containsSubnode(NodeType node) {
    if (subgraph != null) {
      return subgraph.containsSubnode(node);
    }
    return false;
  }

  public NodeType findNodeByName(String name) {
    if (subgraph != null) {
      return subgraph.findNodeByName(name);
    } else {
      return null;
    }
  }

  public NodeType findNodeByName(String name, boolean deep) {
    if (subgraph != null) {
      return subgraph.findNodeByName(name, deep);
    } else {
      return null;
    }
  }

  public EdgeType findEdgeByName(String name) {
    if (subgraph != null) {
      return subgraph.findEdgeByName(name);
    } else {
      return null;
    }
  }

  public EdgeType findEdgeByName(String name, boolean deep) {
    if (subgraph != null) {
      return subgraph.findEdgeByName(name, deep);
    } else {
      return null;
    }
  }

  public Subgraph findSubgraphByName(String name) {
    if (subgraph != null) {
      return subgraph.findSubgraphByName(name);
    } else {
      return null;
    }
  }

  public Subgraph findSubgraphByName(String name, boolean deep) {
    if (subgraph != null) {
      return subgraph.findSubgraphByName(name, deep);
    } else {
      return null;
    }
  }

  public Iterator<NodeType> nodes() {
    if (subgraph != null) {
      return subgraph.nodes();
    } else {
      return null;
    }
  }

  public Iterator<EdgeType> edges() {
    if (subgraph != null) {
      return subgraph.edges();
    } else {
      return null;
    }
  }

  public Iterator<Subgraph<NodeType, EdgeType>> subgraphs() {
    if (subgraph != null) {
      return subgraph.subgraphs();
    } else {
      return null;
    }
  }

  public Set<NodeType> getNodeSet() {
    if (subgraph != null) {
      return subgraph.getNodeSet();
    }
    return null;
  }

  public Set<EdgeType> getEdgeSet() {
    if (subgraph != null) {
      return subgraph.getEdgeSet();
    }
    return null;
  }

  public Set<Subgraph<NodeType, EdgeType>> getSubgraphSet() {
    if (subgraph != null) {
      return subgraph.getSubgraphSet();
    }
    return null;
  }

  public Set<EdgeType> leavingEdges(NodeType node) {
    if (subgraph != null) {
      return subgraph.leavingEdges(node);
    } else {
      return null;
    }
  }

  public Set<EdgeType> leavingEdges(NodeType node, int edgeType) {
    if (subgraph != null) {
      return subgraph.leavingEdges(node, edgeType);
    } else {
      return null;
    }
  }

  public Set<EdgeType> arrivingEdges(NodeType node) {
    if (subgraph != null) {
      return subgraph.arrivingEdges(node);
    } else {
      return null;
    }
  }

  public Set<EdgeType> arrivingEdges(NodeType node, int edgeType) {
    if (subgraph != null) {
      return subgraph.arrivingEdges(node, edgeType);
    } else {
      return null;
    }
  }

  public int getDegree(NodeType node) {
    if (subgraph != null) {
      return subgraph.getDegree(node);
    } else {
      return 0;
    }
  }

  public int getInDegree(NodeType node) {
    if (subgraph != null) {
      return subgraph.getInDegree(node);
    } else {
      return 0;
    }
  }

  public int getOutDegree(NodeType node) {
    if (subgraph != null) {
      return subgraph.getOutDegree(node);
    } else {
      return 0;
    }
  }

  public NodeType searchNode(Point2D p) {
    if (subgraph != null) {
      return subgraph.searchNode(p);
    } else {
      return null;
    }
  }

  public void move(int dx, int dy) {
    if (subgraph != null) {
      subgraph.move(dx, dy);
    }
  }

  public Rectangle2D getBounds() {
    return subgraph.getBounds();
  }

  public void setNodeAttribute(String name, Object value) {
    if (subgraph != null) {
      subgraph.setNodeAttribute(name, value);
    }
  }

  public void removeNodeAttribute(String name) {
    if (subgraph != null) {
      subgraph.removeNodeAttribute(name);
    }
  }

  public Object getNodeAttribute(String key) {
    if (subgraph != null) {
      return subgraph.getNodeAttribute(key);
    } else {
      return null;
    }
  }

  public void setEdgeAttribute(String name, Object value) {
    if (subgraph != null) {
      subgraph.setEdgeAttribute(name, value);
    }
  }

  public void removeEdgeAttribute(String name) {
    if (subgraph != null) {
      subgraph.removeEdgeAttribute(name);
    }
  }

  public Object getEdgeAttribute(String key) {
    if (subgraph != null) {
      return subgraph.getEdgeAttribute(key);
    } else {
      return null;
    }
  }

  public void printSubgraph(PrintWriter out) {
    if (subgraph != null) {
      subgraph.printSubgraph(out);
    }
  }

  public void printSubgraph(int level) {
    if (subgraph != null) {
      subgraph.printSubgraph(level);
    }
  }

  public void writeSubgraphXML(CodeWriter out, String namespacePrefix) {
    if (subgraph != null && !subgraph.isEmpty()) {
      subgraph.writeSubgraphXML(out, namespacePrefix);
    }
  }

  public void buildSubgraphFromXML(org.w3c.dom.Node node, String uri0,
				   Map<String, Object> compShapeMap) {
    if (subgraph != null) {
      subgraph.buildSubgraphFromXML(node, uri0, compShapeMap);
    }
  }

  protected Subgraph<NodeType, EdgeType> subgraph;

  protected boolean expanded;

}
